﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using FileMonitor.Configuration.Prototype;
using FileMonitor.Configuration.Prototype.BizProcess;
using FileMonitor.Configuration.Prototype.Provider;
using FileUtility;

namespace FileMonitor.Configuration.Providers
{
    public class XMLProvider : IProvider
    {

        private readonly string _xmlPath;
        private readonly XElement root;

        private Dictionary<string, Type> _dicTypesCached;
        
        private object lockObjTypes = new object();
        private object lockObjDB = new object();
        
        public XMLProvider(string XMLPath)
        {
            this._xmlPath = XMLPath;
            root = XElement.Load(XMLPath);
        }

        #region IBizProcessProvider Memebers
        public Dictionary<string, CSharpProcessBase> GetAllCSharpProcess()
        {
            Dictionary<string, CSharpProcessBase> dicCSharpProcess = new Dictionary<string, CSharpProcessBase>();
            if (root != null)
            {
                root.Element("businessLogicPeocesses").Element("cSharpProcesses").Elements("add")
                    .ToList().ForEach(item =>
                    {
                        string name = item.Attribute("name").Value;
                        if (name.StartsWith("CSharp_"))
                        {
                            string typeName = item.Attribute("typeName").Value;
                            Type t = this.GetAllTypes()[typeName];
                            if (t != null)
                            {
                                if (t.IsSubclassOf(typeof(CSharpProcessBase)))
                                {
                                    object obj = Activator.CreateInstance(t, new object[] { name });
                                    if (obj != null)
                                    {
                                        CSharpProcessBase cShapObj = obj as CSharpProcessBase;
                                        item.Attributes().ToList().ForEach(at =>
                                        {
                                            if (at.Name != "name")
                                            {
                                                MethodInfo mi = t.GetMethod("set_" + at.Name.LocalName);
                                                if (mi != null)
                                                {
                                                    mi.Invoke(cShapObj, new object[] { at.Value });
                                                }
                                                else
                                                {
                                                    cShapObj.ExtendableConfig.Add(at.Name.LocalName, at.Value);
                                                }
                                            }
                                        });
                                        //  MethodInfo mi= t.GetMethod("set_"+"");
                                        dicCSharpProcess.Add(name, cShapObj);
                                    }
                                }
                            }
                        }
                    });
            }
            return dicCSharpProcess;
        }
        public Dictionary<string, ProcedureProcess> GetAllProcedureProcess()
        {
            Dictionary<string, ProcedureProcess> dicProcedureProcess = new Dictionary<string, ProcedureProcess>();
            if (root != null)
            {
                root.Element("businessLogicPeocesses").Element("procedureProcesses").Elements("add")
                    .ToList().ForEach(item =>
                    {
                        string name = item.Attribute("name").Value;
                        if (name.StartsWith("Procedure_"))
                        {
                            //string ExchangeDB = item.Attribute("ExchangeDB").Value;
                            //string TargetDataBase = item.Attribute("TargetDataBase").Value;
                            //string TargetProcedure = item.Attribute("TargetProcedure").Value;
                            //string BizProcedure = item.Attribute("BizProcedure").Value;
                            //int TimeOut = 1800;
                            //Int32.TryParse(item.Attribute("TimeOut").Value, out TimeOut);

                            ProcedureProcess p = new ProcedureProcess(name);

                            item.Attributes().ToList().ForEach(at =>
                            {
                                if (at.Name != "name")
                                {
                                    MethodInfo method = typeof(ProcedureProcess).GetMethod("set_" + at.Name.LocalName);
                                    if (method != null)
                                    {
                                        method.Invoke(p, new object[] { at.Value });
                                    }
                                    else
                                    {
                                        p.ExtendableConfig.Add(at.Name.LocalName, at.Value);
                                    }
                                }
                            });

                            dicProcedureProcess.Add(name, p);
                        }
                    });

                return dicProcedureProcess;
            }
            return null;
        }
        #endregion

        #region IDatabaseListProvider Memebers
        public Dictionary<string, SqlDataBaseExtender> GetAllDataBase()
        {
            //禁用缓存，防止对象公用。
            //if (_dicDBCached == null)
            //{
            //    lock (lockObjDB)
            //    {
            Dictionary<string, SqlDataBaseExtender> _dicDBs = new Dictionary<string, SqlDataBaseExtender>();
            if (root != null)
            {
                root.Element("connectionStrings").Elements("add")
                    .ToList().ForEach(item =>
                    {
                        string Name = item.Attribute("name").Value;
                        string conStr = item.Attribute("connectionString").Value;
                        SqlDataBaseExtender db = new SqlDataBaseExtender(conStr);
                        _dicDBs.Add(Name, db);
                    });

            }
            //}
            return _dicDBs;

        }
        #endregion

        #region ITypeProvider Memebers
        public Dictionary<string, Type> GetAllTypes()
        {
            //可以使用缓存，返回的是类型，不是真正的Instance。
            if (this._dicTypesCached == null)
            {
                lock (lockObjTypes)
                {
                    if (this._dicTypesCached == null)
                    {
                        _dicTypesCached = new Dictionary<string, Type>();
                        if (root != null)
                        {
                            root.Element("typeProviders").Elements("add")
                                .ToList().ForEach(item =>
                                {
                                    string key = item.Attribute("key").Value;
                                    string value = item.Attribute("value").Value;
                                    string assemblyName = value.Split(",".ToCharArray())[1];
                                    string typeName = value.Split(",".ToCharArray())[0];
                                    Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "/" + assemblyName + ".dll");
                                    if (ass != null)
                                    {
                                        Type t = ass.GetType(typeName);
                                        if (t != null)
                                        {
                                            _dicTypesCached.Add(key, t);
                                        }
                                    }

                                });
                        }
                    }
                }
            }
            return _dicTypesCached;
        }
        #endregion

        #region ISpecialValuesProvider Members
        public NameValueCollection GetAllSpecialValues()
        {
            NameValueCollection values = new NameValueCollection();
            if (root != null)
            {
                root.Element("specialValues").Elements("add")
                    .ToList().ForEach(item =>
                    {
                        string key = item.Attribute("key").Value;
                        string value = item.Attribute("value").Value;
                        values.Add(key, value);
                    });
            }
            return values;
        }
        #endregion

        #region IWorkProcessProvider Members
        public Dictionary<string, WorkProcessBase> GetAllWorkProcess()
        {
            Dictionary<string, WorkProcessBase> dics = new Dictionary<string, WorkProcessBase>();
            if (root != null)
            {
                root.Element("processProviders").Element("processes").Elements("add")
                    .ToList().ForEach(item =>
                    {
                        string name = item.Attribute("name").Value;
                        WorkProcessBase p = new WorkProcessBase(name);
                        item.Attributes().ToList().ForEach(at =>
                        {
                            if (at.Name.LocalName != "name" && at.Name.LocalName != "BizProcesses" && at.Name.LocalName!="type")
                            {
                                p.ExtendableConfig.Add(at.Name.LocalName, at.Value);
                            }
                        });
                        p.TypeValue = this.GetAllTypes()[item.Attribute("typeName").Value];
                        XAttribute bizProcessAttribute = item.Attribute("BizProcesses");
                        if (bizProcessAttribute != null)
                        {
                            string bizExpression = item.Attribute("BizProcesses").Value;
                            if (!string.IsNullOrEmpty(bizExpression))
                            {
                                Dictionary<string, string> dicBizExp = Utility.ParseDictionary(bizExpression);
                                foreach (var pExp in dicBizExp)
                                {
                                    int key = Int32.Parse(pExp.Key);
                                    BizProcessBase bizP = this.GetBizProcssByName(pExp.Value);
                                    p.BizProcesses.Add(key, bizP);
                                }
                                foreach (int key in p.BizProcesses.Keys)
                                {
                                    if (p.BizProcesses.ContainsKey(key + 1))
                                    {
                                        p.BizProcesses[key].NextBizProcess = p.BizProcesses[key + 1];
                                    }
                                }
                            }
                        }

                        dics.Add(name, p);
                    });
            }
            return dics;
        }
        #endregion

        private BizProcessBase GetBizProcssByName(string Name)
        {
            string Prefix = Name.Substring(0, Name.IndexOf("_")).ToUpper();
            if (Prefix == "CSHARP")
            {
                return this.GetAllCSharpProcess()[Name];
            }
            else if (Prefix == "PROCEDURE")
            {
                return this.GetAllProcedureProcess()[Name];
            }
            return null;
        }

    }
}
